package util;

import java.awt.Color;
import java.awt.Point;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

import sprites.ActorSprite;
import sprites.Sprite;

public class MapModel implements Collection<Sprite> {
	//
	// This map is used to determine how to display the world on screen
	//
	
	private TreeSet<Sprite> 				sprites			= new TreeSet<Sprite>();
	private	HashMap<Object, Set<Sprite>>	spritesOfType	= new HashMap<Object, Set<Sprite>>();
	private Set<Point>						selected		= new HashSet<Point>();

	//
	// Colors used for rendering
	//
	private	Color	backColor;
	private Color	foreColor;
	private Color	gridColor;
	private Color	spriteColor;
	private Color	textColor;

	//
	// These methods are used to do more specific queries of sprites that match the specific class
	//	
	protected final Set<Sprite>	getSpritesOfType(Class<? extends Sprite> eClass) {
		if (!spritesOfType.containsKey(eClass)) {
			spritesOfType.put(eClass, new TreeSet<Sprite>());
		}
		return spritesOfType.get(eClass);
	}
	
	public Set<ActorSprite>	getActors() {
		//
		// The most common actor type we need to concern ourselves with
		// this set is used to keep track of initiative order etc.
		//
		Set<ActorSprite>	actors = new TreeSet<ActorSprite>();
		for(Sprite actor : getSpritesOfType(ActorSprite.class)) {
			ActorSprite	a = (ActorSprite) actor;
			actors.add(a);
		}
		return actors;
	}
	
	//
	// Methods to implement as a collection of sprites
	//
	
	@Override
	public int size() {					
		return sprites.size();		
	}

	@Override
	public boolean isEmpty() {
		return sprites.isEmpty();	
	}

	@Override
	public boolean contains(Object o) {
		return sprites.contains(o);	
	}

	@Override
	public Iterator<Sprite> iterator() {
		return sprites.iterator();
	}

	@Override
	public Object[] toArray() {
		return sprites.toArray();
	}

	@Override
	public <T> T[] toArray(T[] a) {
		return sprites.toArray(a);
	}

	@SuppressWarnings("unchecked")
	@Override
	public boolean add(Sprite e) {
		//
		// This will add the sprite to the collection and also to the map of spriteType to nonSpriteType
		//
		boolean	ret = sprites.add(e);
		if (ret) {
			
			//
			// For each class this can represent, add an entry into the class/sprite map
			//
			for(Class<?> eClass : e.getClass().getClasses()) {
				Class<? extends Sprite>	tmpClass = (Class<? extends Sprite>) eClass;
				Set<Sprite>	sameTypeSprites = getSpritesOfType(tmpClass);
				sameTypeSprites.add(e);
			}
		}
		return ret;
	}

	@Override
	public boolean remove(Object e) {
		//
		// This will add the sprite to the collection and also to the map of spriteType to nonSpriteType
		//
		boolean	ret = sprites.remove(e);
		if (ret) {
			
			//
			// For each class this can represent, add an entry into the class/sprite map
			//
			for(Class<?> eClass : e.getClass().getClasses()) {
				if (!spritesOfType.containsKey(e.getClass())) {
					spritesOfType.put(eClass, new TreeSet<Sprite>());
				}
				
				Set<Sprite>	sameTypeSprites = spritesOfType.get(eClass);
				sameTypeSprites.remove(e);
			}
		}
		return ret;
	}

	@Override
	public boolean containsAll(Collection<?> c) {
		return sprites.containsAll(c);
	}

	@Override
	public boolean addAll(Collection<? extends Sprite> c) {
		Iterator<? extends Sprite>	itr = c.iterator();
		boolean		ret = true;
		while(itr.hasNext()) {
			ret = add(itr.next()) && ret;
		}
		return ret;
	}

	@Override
	public boolean removeAll(Collection<?> c) {
		Iterator<?>	itr = c.iterator();
		boolean		ret = true;
		while(itr.hasNext()) {
			ret = remove(itr.next()) && ret;
		}
		return ret;
	}

	@Override
	public boolean retainAll(Collection<?> c) {
		// This currently does nothing. It is not important to us.
		return false;
	}

	@Override
	public void clear() {
		sprites.clear();
		spritesOfType.clear();
	}
	
	//
	// Getters and Setters for common colors
	//

	public Color getGridColor() {
		return gridColor;
	}

	public void setGridColor(Color gridColor) {
		this.gridColor = gridColor;
	}

	public Color getForeColor() {
		return foreColor;
	}

	public void setForeColor(Color foreColor) {
		this.foreColor = foreColor;
	}

	public Color getBackColor() {
		return backColor;
	}

	public void setBackColor(Color backColor) {
		this.backColor = backColor;
	}

	public Color getSpriteColor() {
		return spriteColor;
	}

	public void setSpriteColor(Color spriteColor) {
		this.spriteColor = spriteColor;
	}

	public Color getTextColor() {
		return textColor;
	}

	public void setTextColor(Color textColor) {
		this.textColor = textColor;
	}

	public Set<Point> getSelected() {
		return selected;
	}

	public void setSelected(Set<Point> selected) {
		this.selected = selected;
	}
	
	
	
}



